//
//  CalculateAreaUtil.swift
//  AreaMeasureDevice
//
//  Created by iOS on 2021/5/19.
//

import Foundation
import MapKit
import AMapFoundationKit

class CalcuLateAreaUtil {

    /// 单位精度对应的长度
    var zero_cosdist:Double = 0

    private var pn:Int = 0, phase:Int = 0, pn1:Int = 0, pn2:Int = 0
    private var jd1:Double = 0, wd1:Double = 0, jd2:Double = 0, wd2:Double = 0
    private var S1:Double = 0, S2:Double = 0, SZ:Double = 0, SF:Double = 0, SS:Double = 0, S:Double = 0

    private var orgin_lat:Double =  0, orgin_lon:Double = 0, old_lat:Double = 0, old_lon:Double = 0, current_lat:Double = 0, current_lon:Double = 0

    static let EARTH_RADIUS = 6378.137

    var JZ_area:Double = 0

    /// 计算两个经纬度间的距离
    func measurePerimeter(locatins:[CLLocationCoordinate2D]) -> Double {
        var perimeter:Double = 0
        if locatins.count >= 2 {
            let point1 = MAMapPointForCoordinate(locatins[locatins.count-2])
            let point2 = MAMapPointForCoordinate(locatins[locatins.count-1])
            perimeter = MAMetersBetweenMapPoints(point1, point2)
            return perimeter
        }
        return 0
    }

    /// 计算AB两点距离
    func measurePerimeterA_B(points:[CLLocationCoordinate2D]) -> Double {
        var perimeterA_B:Double = 0
        if points.count == 2 {
            let frontPoint = CLLocation(latitude: points[0].latitude, longitude: points[0].longitude)
            let afterPoint = CLLocation(latitude: points[1].latitude, longitude: points[1].longitude)
            perimeterA_B = abs(frontPoint.distance(from: afterPoint))
            return perimeterA_B
        }
        return 0
    }

    /// 计算BC两点距离
    /// - Parameter points: 源数据
    /// - Returns: 距离
    func measurePerimeterB_C(points:[CLLocationCoordinate2D]) -> Double {
        var perimeterB_C:Double = 0
        if points.count == 3 {
            let frontPoint = CLLocation(latitude: points[1].latitude, longitude: points[1].longitude)
            let afterPoint = CLLocation(latitude: points[2].latitude, longitude: points[2].longitude)
            perimeterB_C = abs(frontPoint.distance(from: afterPoint))
            return perimeterB_C
        }
        return 0
    }

    /// 设置角度计算面积
    func caculateSlopeLandArea(area:Double, angle:Double) -> Double {
        let radians = self.radians(d: angle)
        return area / cos(radians)
    }
    /// 设置宽度计算面积
    func caculateWidthLandArea(area:Double, perimeter:Double, width:Double) -> Double{
        return area + fabs(perimeter * width / 10)
    }

    /// 通过向量法进行计算面积
    func getArea(coords:[CLLocationCoordinate2D]) -> Double {
        if coords.count > 2 {
            current_lon = coords[coords.count - 1].longitude * 3600
            current_lat = coords[coords.count - 1].latitude * 3600

            old_lon = coords[coords.count - 2].longitude * 3600
            old_lat = coords[coords.count - 2].latitude * 3600

            orgin_lon = coords[0].longitude * 3600
            orgin_lat = coords[0].latitude * 3600

            // 上一个点与原点的经度的向量值
            if old_lon >= orgin_lon {
                // 计算向量值
                jd1 = decimal(value1: old_lon, value2: orgin_lon) * zero_cosdist //一秒精度的距离差  单位是厘米
                pn = 0x00
            }else{
                jd1 = decimal(value1: orgin_lon, value2: old_lon) * zero_cosdist
                pn = 0x01
            }
            // 上一个点与原点的纬度的向量值
            if old_lat >= orgin_lat {
                wd1 = decimal(value1: old_lat, value2: orgin_lat) * 31
                pn = pn & 0xfd
            }else{
                wd1 = decimal(value1: orgin_lat, value2: old_lat) * 31
                pn = pn | 0x02
            }

            // 当前点与原点的经度的向量值
            if current_lon >= orgin_lon {
                jd2 = decimal(value1: current_lon, value2: orgin_lon) * zero_cosdist // 一秒经度对应的距离差  单位米
                pn = pn & 0xfb
            }else{
                jd2 = decimal(value1: orgin_lon, value2: current_lon) * zero_cosdist
                pn = pn | 0x04
            }
            // 当前点与原点纬度的向量值
            if current_lat >= orgin_lat {
                wd2 = decimal(value1: current_lat, value2: orgin_lat) * 31 //一秒纬度度对应的距离差  单位米
                pn = pn & 0xf7
            }else{
                wd2 = decimal(value1: orgin_lat, value2: current_lat) * 31
                pn = pn | 0x08
            }

            // 计算与零点正负关系
            if (pn & 0x01) != 0 {
                pn1 = 1
            }else{
                pn1 = 0
            }

            if (pn & 0x08) != 0 {
                pn2 = 1
            }else{
                pn2 = 0
            }

            if pn1 == pn2 {
                phase = 0x00 // S1的数据是正
            }else{
                phase = 0x01 // 最低位为S1的符号，确定S1是正还是负，正
            }

            if (pn & 0x02) != 0 {
                pn1 = 1
            }else{
                pn1 = 0
            }

            if (pn & 0x04) != 0 {
                pn2 = 1
            }else{
                pn2 = 0
            }

            if pn1 == pn2 {
                phase = phase & 0xfd
            }else{
                phase = phase | 0x02
            }

            S1 = jd1 * wd2 // 转换成平方米，每次都应该是S1-S2才对
            S2 = jd2 * wd1 // 乘积做出来单位为平方厘米

            switch phase { // 有些正负是可以认为在同一点上，需要采用必要的消除误差的办法来解决
                case 0:
                    if S1 >= S2 {
                        SZ = SZ + S1 - S2 // 应该就是S1-S2，如果当前的面积是正
                    }else{
                        SF = SF + S2 - S1
                    }
                case 1:
                    SF = SF + S2 + S1
                case 2:
                    SZ = SZ + S1 + S2
                case 3:
                    if S1 >= S2 {
                        SF = SF + S1 - S2 // 两个都是负数
                    }else{
                        SZ = SZ + S2 - S1
                    }
                default:
                    break
            }

            if SZ >= SF {
                S = SZ - SF
                SZ = S // 总的面积有可能会变大，也可能会变小
                SF = 0
            }else{
                S = SF - SZ
                SF = S
                SZ = 0
            }
            return S
        }
        return 0
    }


    /// 计算面积
    /// - Parameters:
    ///   - start: 开始点
    ///   - latestone: 当前点
    ///   - latesttwo: 上一点
    /// - Returns: 面积（平方米）
    func getTriangleArea(start:CLLocationCoordinate2D, latestone:CLLocationCoordinate2D, latesttwo:CLLocationCoordinate2D) -> Double {
        ///以下的所有的经纬度坐标为秒的1000倍（纬度千分之一秒为3.1厘米)
        /// 一秒为 31 米

        current_lon = latestone.longitude * 3600000
        current_lat = latestone.latitude * 3600000

        old_lon = latesttwo.longitude * 3600000
        old_lat = latesttwo.latitude * 3600000

        orgin_lon = start.longitude * 3600000
        orgin_lat = start.latitude * 3600000

        // 上一个点与原点的经度的向量值
        if old_lon >= orgin_lon {
            // 计算向量值
            jd1 = floor(MathTool.multiply(x: decimal(value1: old_lon, value2: orgin_lon), y: zero_cosdist) / 100) //一秒精度的距离差  单位是厘米
            pn = pn & 0xfe
        }else{
            jd1 = floor(MathTool.multiply(x: decimal(value1: orgin_lon, value2: old_lon), y: zero_cosdist) / 100)
            pn = pn | 0x01
        }
        // 上一个点与原点的纬度的向量值
        if old_lat >= orgin_lat {
            wd1 = floor(MathTool.multiply(x: decimal(value1: old_lat, value2: orgin_lat), y: 308)/100)
            pn = pn & 0xfd
        }else{
            wd1 = floor(MathTool.multiply(x: decimal(value1: orgin_lat, value2: old_lat), y: 308)/100)
            pn = pn | 0x02
        }

        // 当前点与原点的经度的向量值
        if current_lon >= orgin_lon {
            jd2 = floor(MathTool.multiply(x: decimal(value1: current_lon, value2: orgin_lon), y: zero_cosdist)/100) // 一秒经度对应的距离差  单位米
            pn = pn & 0xfb
        }else{
            jd2 = floor(MathTool.multiply(x: decimal(value1: orgin_lon, value2: current_lon), y: zero_cosdist)/100)
            pn = pn | 0x04
        }
        // 当前点与原点纬度的向量值
        if current_lat >= orgin_lat {
            wd2 = floor(MathTool.multiply(x: decimal(value1: current_lat, value2: orgin_lat), y: 308)/100) //一秒纬度度对应的距离差  单位米
            pn = pn & 0xf7
        }else{
            wd2 = floor(MathTool.multiply(x: decimal(value1: orgin_lat, value2: current_lat), y: 308)/100)
            pn = pn | 0x08
        }

        debugPrint("计算出：jd1=\(jd1), wd1=\(wd1) \n jd2 = \(jd2), wd2=\(wd2)")

        // 计算与零点正负关系
        if (pn & 0x01) != 0 {
            pn1 = 1
        }else{
            pn1 = 0
        }

        if (pn & 0x08) != 0 {
            pn2 = 1
        }else{
            pn2 = 0
        }

        if pn1 == pn2 {
            phase = phase & 0xfe // S1的数据是正
        }else{
            phase = phase | 0x01 // 最低位为S1的符号，确定S1是正还是负，正
        }

        if (pn & 0x02) != 0 {
            pn1 = 1
        }else{
            pn1 = 0
        }

        if (pn & 0x04) != 0{
            pn2 = 1
        }else{
            pn2 = 0
        }

        if pn1 == pn2 {
            phase = phase & 0xfd
        }else{
            phase = phase | 0x02
        }

        S1 = MathTool.multiply(x: jd1, y: wd2)// 转换成平方米，每次都应该是S1-S2才对
        S2 = MathTool.multiply(x: jd2, y: wd1) // 乘积做出来单位为平方厘米

        debugPrint("计算出：S1 == \(S1)" + "S2 == \(S2)")
        debugPrint("phase === ", phase)

        switch phase { // 有些正负是可以认为在同一点上，需要采用必要的消除误差的办法来解决
            case 0:
                if S1 >= S2 {
                    SZ = MathTool.add(x: SZ, y: rint(decimal(value1: S1, value2: S2)/10000)) // 应该就是S1-S2，如果当前的面积是正
                }else{
                    SF = MathTool.add(x: SF, y: rint(decimal(value1: S2, value2: S1)/10000))
                }
            case 1:
                SF = MathTool.add(x: SF, y: rint(MathTool.add(x: S1, y: S2)/10000))
            case 2:
                SZ = MathTool.add(x: SZ, y: rint(MathTool.add(x: S1, y: S2)/10000))
            case 3:
                if S1 >= S2 {
                    SF = MathTool.add(x: SF, y: rint(decimal(value1: S1, value2: S2)/10000)) // 两个都是负数
                }else{
                    SZ = MathTool.add(x: SZ, y: rint(decimal(value1: S2, value2: S1)/10000))
                }
            default:
                break
        }
        debugPrint("计算出：SF == \(SF)" + "SZ == \(SZ)")
        if SZ >= SF {
            SS = decimal(value1: SZ, value2: SF)
            SZ = SS // 总的面积有可能会变大，也可能会变小
            S = SS
            SF = 0
        }else{
            SS = decimal(value1: SF, value2: SZ)
            SF = SS
            S = SS
            SZ = 0
        }
        debugPrint("计算出：S == \(S)")
        return S
    }

    func decimal(value1:Double, value2:Double) -> Double {
        let decimal1 = Decimal(string: String(value1))
        let decimal2 = Decimal(string: String(value2))
        let value = decimal1! - decimal2!
        return Double(truncating: value as NSNumber)
    }

    /// 计算弧度
    func radians(d:Double) -> Double {
        return d * .pi / 180
    }

}
